﻿using System;
using System.Net;
using System.IO;
using System.Collections;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using WFFS;
using System.Windows.Forms;
using System.Drawing;

//The Network Protocol consists of the following
namespace WhiteBoard
{
    //网络模式的枚举
    public enum SOKET_TYPE
    {
        enServerMode,
        enClientMode
    };
    /// <summary>
    /// Summary description for NetworkManager.
    /// </summary>
    /// 
    public class NetworkManager
    {
        //Server Mode
        private Socket serverSocket;//服务器的socket
        private int port;//端口
        private String ip;//端口
        private String localIp;//连接上服务器IP
        public SOKET_TYPE soketType;//管理模式
        private bool stoppedListening;//是否停止监听
        public Hashtable connectingClientHandlers = new Hashtable(); //客户端ClientHandler集合
        public ClientHandler clientHandler;//客户端模式时连接的ClientHandler 消息处理类
        public FrmSound frm_Sound;//声音窗口
        public Form1 frm_Main;//窗口
        /////////////////////////////////////////////////服务器端模式代码////////////////////
        //初始化网络管理
        public NetworkManager(string ip, string iPort, SOKET_TYPE enAppMode)
        {
            stoppedListening = true;
            port = Convert.ToInt32(iPort);
            this.ip = ip;
            soketType = enAppMode;
        }

        //Server related methods (App behaves as a Server by opening up a listening port)
        public void StartListening()
        {
            soketType = SOKET_TYPE.enServerMode;//服务器模式
            string StrHostName = Dns.GetHostName();
            serverSocket = new Socket(0, SocketType.Stream, ProtocolType.Tcp);
            IPAddress hostadd = Dns.Resolve(ip).AddressList[0];
            IPEndPoint LocEndpoint = new IPEndPoint(hostadd, port);
            serverSocket.Bind(LocEndpoint);
            serverSocket.Blocking = true;
            serverSocket.Listen(10);
            //开始接受连接，异步。
            serverSocket.BeginAccept(new AsyncCallback(this.OnConnectRequest), serverSocket);
            stoppedListening = false;
            frm_Main.SetMusicalStatus("conn", "已启动");
        }
        //当有客户端连接时的处理
        public void OnConnectRequest(IAsyncResult ar)
        {
            try
            {
                Socket sockListener = (Socket)ar.AsyncState;
                if (!stoppedListening)
                {//如果没有停止监听
                    Socket sockClient = sockListener.EndAccept(ar);
                    String ip = sockClient.RemoteEndPoint.ToString();
                    ClientHandler connectingClientHandler = new ClientHandler(sockClient);
                    connectingClientHandler.frm_Main = frm_Main;
                    connectingClientHandler.frm_Sound = frm_Sound;
                    connectingClientHandler.beginReadSocket();//开始读取客户端发来的信息                    
                    connectingClientHandlers.Add(ip, connectingClientHandler);
                    //  frm_Main.SetMusicalStatus("");//客户端连接
                    ///当有客户端连接上来，向连接上的客户端---
                    // 设置当前白板的背景
                    if (this.frm_Main.Drawing.Image != null){   
                        WBMsgDrawingImage wBMsgDrawingImage = new WBMsgDrawingImage();
                        wBMsgDrawingImage.path = this.frm_Main.path;
                        SendWBMsgConnectedHdlr(wBMsgDrawingImage);
                    }
                    //设置画笔颜色
                    WBMsgDrawStyle drawStyle = new WBMsgDrawStyle();
                    drawStyle.drawColor = this.frm_Main.drawColor;
                    drawStyle.lineWidth = this.frm_Main.lineWidth;
                    SendWBMsgConnectedHdlr(drawStyle);
                    //清楚客户端以前画的图
                    WBMsgClearScreen screen = new WBMsgClearScreen();
                    SendWBMsgConnectedHdlr(screen);
                    //等待新的客户端连接
                    sockListener.BeginAccept(new AsyncCallback(this.OnConnectRequest), sockListener);
                }
            }
            catch (Exception e)
            {
                //  MessageBox.Show(e.Message);
            }

        }
        /// <summary>
        /// 使用ClientHandler异步发送消息 
        ///  向所有的客户端发送消息
        /// </summary>
        /// <param name="msg"></param>
        public void SendWBMsgConnectedHdlr(WBMessage msg)
        {
            switch (soketType)
            {
                case SOKET_TYPE.enServerMode:  //服务器模式
                    foreach (DictionaryEntry de in connectingClientHandlers)
                    {
                        ClientHandler connectingClientHandler = (ClientHandler)de.Value;

                        if (connectingClientHandler != null)
                        {
                            if (connectingClientHandler.socket != null)
                                connectingClientHandler.SendWBMessage(msg);
                        }
                    }
                    break;
                case SOKET_TYPE.enClientMode://客户端模式
                    if (clientHandler != null && clientHandler.socket != null)
                    {
                        clientHandler.SendWBMessage(msg);
                    }
                    break;
            }
        }
        /// <summary>
        /// 使用ClientHandler异步发送消息
        /// 向指定的客户端IP发送消息
        /// </summary>
        /// <param name="msg"></param>
        public void SendWBMsgConnectedHdlr(WBMessage msg, Hashtable ipTable)
        {
            switch (soketType)
            {
                case SOKET_TYPE.enServerMode:  //服务器模式
                    foreach (DictionaryEntry de in connectingClientHandlers)
                    {
                        String ip = ((String)de.Key).Split(':')[0];
                        if (ipTable[ip] != null)
                        {
                            ClientHandler connectingClientHandler = (ClientHandler)de.Value;
                            if (connectingClientHandler != null)
                            {
                                if (connectingClientHandler.socket != null)
                                    connectingClientHandler.SendWBMessage(msg);
                            }
                        }
                    }
                    break;
                case SOKET_TYPE.enClientMode://客户端模式
                    if (clientHandler != null && clientHandler.socket != null)
                    {
                        clientHandler.SendWBMessage(msg);
                    }
                    break;
            }
        }
        //////////////////////客户端模式/////////////////////////////

        //连接到服务器
        public Boolean ConnectToListeningServer()
        {
            try
            {
                soketType = SOKET_TYPE.enClientMode;//客户端
                IPAddress hostadd = Dns.Resolve(ip).AddressList[0];
                int iHostPort = Convert.ToInt32(port);
                IPEndPoint EPhost = new IPEndPoint(hostadd, iHostPort);
                Socket clientSocket = new Socket(AddressFamily.InterNetwork,
                    SocketType.Stream,
                    ProtocolType.Tcp
                    );
                clientSocket.Connect(EPhost);
                frm_Main.SetMusicalStatus("conn", "已连接");//客户端连接成功后声音与文字提醒
                clientHandler = new ClientHandler(clientSocket);
                clientHandler.frm_Main = frm_Main;
                clientHandler.frm_Sound = frm_Sound;
                clientHandler.beginReadSocket();
                //  MessageBox.Show("服务器连接成功");
                return true;
            }
            catch (Exception e)
            {
                //  MessageBox.Show("服务器连接失败");
                return false;
            }

        }

        //关闭连接
        public void Disconnect()
        {
            switch (soketType)
            {
                case SOKET_TYPE.enServerMode://服务器模式 关闭所有的连接
                    //关闭时向所有的客户端发送通知
                    foreach (DictionaryEntry de in connectingClientHandlers)
                    {
                        ClientHandler connectingClientHandler = (ClientHandler)de.Value;
                        if (connectingClientHandler != null)
                        {
                            if (connectingClientHandler.socket != null)
                            {
                                WBMsgCloseSoket closesoket = new WBMsgCloseSoket();
                                connectingClientHandler.SendWBMessage(closesoket);
                            }
                        }
                    }
                    if (serverSocket != null)
                    {
                        serverSocket.Close();
                        serverSocket = null;
                    }
                    stoppedListening = true;
                    connectingClientHandlers = new Hashtable(); //清楚连接列表
                    frm_Main.SetMusicalStatus("stop", "未启动");
                    break;
                case SOKET_TYPE.enClientMode://客户端模式
                    if (clientHandler != null)
                    {
                        if (clientHandler.socket == null)
                        {
                            clientHandler = null;
                        }
                        else
                            if (clientHandler.socket.Connected)
                            {
                                clientHandler.DisconnectClient();
                                clientHandler = null;
                            }
                    }
                    frm_Main.SetMusicalStatus("stop", "未连接");
                    break;
            }
        }
    }
    ////////////////////////////////////////////////////////////////////////////////////
    //自定义soket的消息异步读取类
    public class ClientHandler
    {
        public Socket socket;//socket
        //Deals with the Async socket IO
        private AsyncCallback m_AsyncCallbackRead;//异步读取:回调异步调用结束后的自定义函数
        private AsyncCallback m_AsyncCallbackWrite;//异步写入:用于回调异步调用结束后的自定义函数
        private NetworkStream m_NS;
        private byte[] m_ByteBuf;
        private byte[] m_ByteCache;
        private int readLength = 926234;//消息读取错误
        public Form1 frm_Main;   //主窗口
        public FrmSound frm_Sound;//声音窗口
        private delegate void DelAddPeersTreeViewNode(string StrNode);
        private delegate void DelClearPeersTreeView();

        public ClientHandler(Socket SockClient)
        {
            //frm_Main = ParentForm;
            socket = SockClient;
            m_ByteBuf = new Byte[readLength];
            m_NS = new NetworkStream(socket, FileAccess.ReadWrite);

            //Initialize the AsyncCallback delegate
            m_AsyncCallbackRead = new AsyncCallback(this.OnReadComplete);
            m_AsyncCallbackWrite = new AsyncCallback(this.OnWriteComplete);
            m_ByteCache = new Byte[readLength * 2];
            m_iByteCacheLen = 0;
            m_bOnHeader = true;
            m_iDataPackLen = 0;
        }
        //写入函数（发送消息）
        public void SendWBMessage(WBMessage msg)
        {
            if (m_NS != null)
            {
                MemoryStream ms = WBMessageHelper.Serialize(msg);
                MemoryStream msLength = WBMessageHelper.Serialize(ms.Length);
                m_NS.BeginWrite(msLength.GetBuffer(), 0, (int)msLength.Length, m_AsyncCallbackWrite, null);
                m_NS.BeginWrite(ms.GetBuffer(), 0, (int)ms.Length, m_AsyncCallbackWrite, null);
                ms.Close();
                msLength.Close();
            }
        }
        //开始读取soket发来的信息
        public void beginReadSocket()
        {
            m_NS.BeginRead(m_ByteBuf, 0, m_ByteBuf.Length, m_AsyncCallbackRead, null);

        }

        //异步读取调用结束后的函数
        private void OnReadComplete(IAsyncResult ar)
        {
            try
            {
                int CbRead = m_NS.EndRead(ar);
                //本节清楚假定来自客户端的数据不超过1024
                if (CbRead > 0)
                {
                    if (m_iByteCacheLen > 0)
                    {

                        byte[] ByteBuffTemp = new byte[CbRead + m_iByteCacheLen];
                        Array.Copy(m_ByteBuf, 0, m_ByteCache, m_iByteCacheLen, CbRead);
                        CbRead += m_iByteCacheLen;
                        Array.Copy(m_ByteCache, 0, ByteBuffTemp, 0, CbRead);
                        ParseData(ByteBuffTemp, CbRead);
                    }
                    else
                    {
                        ParseData(m_ByteBuf, CbRead);
                    } m_NS.BeginRead(m_ByteBuf, 0, m_ByteBuf.Length, m_AsyncCallbackRead, null);

                }
                else
                {
                    DisconnectClient();
                }
            }
            catch (Exception e){
                //  this.frm_Main.SetMusicalStatus("stop", "未连接");
                //     MessageBox.Show("异步读取数据错误:" + e.Message);
                DisconnectClient();
            }
        }
        //异步写入调用结束后的函数
        private void OnWriteComplete(IAsyncResult ar)
        {
            m_NS.EndWrite(ar);
        }
        private int m_iByteCacheLen;
        private bool m_bOnHeader;
        private int m_iDataPackLen;
        private const int m_iHdrSize = 56;
        public void ParseData(byte[] ByteBuff, int iCbRead)
        {
            int offset = 0;
            //long lLenData = 0;
            m_iByteCacheLen = 0;

            while (iCbRead >= m_iHdrSize)
            {
                if (m_bOnHeader)
                {
                    m_iDataPackLen = (int)WBMessageHelper.DeserializeL(ByteBuff, offset, m_iHdrSize);
                    offset += m_iHdrSize;
                    m_bOnHeader = false;
                    iCbRead -= m_iHdrSize;
                }
                //Parse the data 
                else
                {
                    if (m_iDataPackLen == 0) return;
                    if (m_iDataPackLen > iCbRead)
                    {
                        Array.Clear(m_ByteCache, 0, readLength * 2);
                        Array.Copy(ByteBuff, offset, m_ByteCache, 0, iCbRead);
                        m_iByteCacheLen = iCbRead;
                        iCbRead -= iCbRead;
                        //break;
                    }
                    else
                    {
                        WBMessage msg = WBMessageHelper.Deserialize(ByteBuff, offset, m_iDataPackLen);
                        RouteRequest(msg);
                        offset += m_iDataPackLen;
                        m_iByteCacheLen = 0;
                        iCbRead -= m_iDataPackLen;
                        m_iDataPackLen = 0;
                        m_bOnHeader = true;
                    }
                }
            }
            //This is where we have surplus/incomplete data packets
            if (iCbRead > 0)
            {
                Array.Clear(m_ByteCache, 0, 2048);
                Array.Copy(ByteBuff, offset, m_ByteCache, 0, iCbRead);
                m_iByteCacheLen = iCbRead;
            }

        }

        //读取消息后的，对应系统的处理
        public void RouteRequest(WBMessage msg)
        {
            try
            {
                switch (msg.MessageType)
                {
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.enWBBack:
                        frm_Main.WhenBack();
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.enWBProceed:
                        frm_Main.WhenProceed();
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.DrawStyle:
                        WBMsgDrawStyle WBMsgDrawStyle = (WBMsgDrawStyle)msg;
                        frm_Main.whenSetPen(WBMsgDrawStyle.drawColor, WBMsgDrawStyle.lineWidth);
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.DrawMouseDown:
                        WBMsgDrawMouseDown msgDrawMouseDown = (WBMsgDrawMouseDown)msg;
                        frm_Main.WhenMouseDown(msgDrawMouseDown.startPoint);
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.DrawMouseUp:
                        WBMsgDrawMouseUp msgDrawMouseUp = (WBMsgDrawMouseUp)msg;
                        frm_Main.WhenMouseUp(msgDrawMouseUp.endPoint);
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.DrawMouseMove:
                        WBMsgDrawMouseMove msgDrawMouseMove = (WBMsgDrawMouseMove)msg;
                        frm_Main.WhenMouseMove(msgDrawMouseMove.movPoint);
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.UiDrafting_DragDrop:
                        WBMsgUiDrafting_DragDrop wBMsgUiDrafting_DragDrop = (WBMsgUiDrafting_DragDrop)msg;
                        frm_Main.UiDraftingControl_DragDrop(wBMsgUiDrafting_DragDrop.name, wBMsgUiDrafting_DragDrop.text, wBMsgUiDrafting_DragDrop.p);
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.UiMove_MouseDown:
                        WBMsgUiMove_MouseDown msgUiMove_MouseDown = (WBMsgUiMove_MouseDown)msg;
                        frm_Main.whenUiMove_MouseDown(msgUiMove_MouseDown.p);
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.UiMove_MouseMove:
                        WBMsgUiMove_MouseMove msgUiMove_MouseMove = (WBMsgUiMove_MouseMove)msg;
                        frm_Main.whenUiMove_MouseMove(msgUiMove_MouseMove.name, msgUiMove_MouseMove.button, msgUiMove_MouseMove.mousePos);
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.UiMove_MouseUp:
                        WBMsgUiMove_MouseUp msgUiMove_MouseUp = (WBMsgUiMove_MouseUp)msg;
                        frm_Main.whenUiMove_MouseUp();
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.WBClearScreen:
                        frm_Main.clearScreen();
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.DrawingImage:
                        WBMsgDrawingImage wBMsgDrawingImage = (WBMsgDrawingImage)msg;
                        frm_Main.whenSetImage(wBMsgDrawingImage);
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.ImageUpdate:
                        WBMsgImageUpdate wBMsgImageUpdate = (WBMsgImageUpdate)msg;
                        frm_Main.whenUploadImage(wBMsgImageUpdate.im, wBMsgImageUpdate.name);
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.allDirective:
                        WBMsgAllDirective allDirective = (WBMsgAllDirective)msg;
                        frm_Main.allDirective(allDirective);
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.CloseSoket:
                        frm_Main.SetMusicalStatus("stop", "服务器已停止");
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.DrawImage:
                        DrawImage drawImage = (DrawImage)msg;
                        frm_Main.DrawImage(drawImage);
                        break;
                    case WBMessage.WHITEBOARD_MESSAGE_TYPE.enWBDeleteButton:
                        enWBDeleteButton enWBDeleteButton = (enWBDeleteButton)msg;
                        frm_Main.WhenUiDelete(enWBDeleteButton.name);
                        break;

                        

                }
            }
            catch (Exception excp)
            {
                //  MessageBox.Show("消息处理错误:" + excp.Message);
            }
        }
        public void DisconnectClient()
        {
            m_NS.Close();
            socket.Close();
            m_NS = null;
            socket = null;
        }
    }

}
